package logo.utils;

/** This class implements a bounded capacity FIFO queue.  Access to
    its elements is synchronised so that this queue may be safely used
    in concurrent processing, without requiring any additional
    precautions to be exercised by the user.
*/
public class Queue {

    public static int DEFAULT_CAPACITY = 8192;
    protected final int CAPACITY;

    private Object[] data;
    private int head;
    private int tail;

    public Queue() {
	this(DEFAULT_CAPACITY);
    }

    public Queue(int c) {
	CAPACITY = c;
	data = new Object[CAPACITY];
	head = 0;
	tail = 0;
    }

    /** Flushes this queue without processing the elements, making it
	immediately empty */
    public synchronized void clear() {
	data = new Object[CAPACITY];
	head = 0;
	tail = 0;
    }

    /** Returns true if there are no items currently enqueued on this queue. */
    public synchronized boolean isEmpty() {
	return (head == tail);
    }

    /** Return the number of items enqueued */
    public synchronized int length() {
	if (head <= tail)	// no wraparound
	    return tail - head;
	else
	    return CAPACITY + tail - head;
    }

    /** Add a value at the end of the queue */
    public synchronized void enqueue(Object item) throws QueueFullException {
	int newTail = (tail + 1) % CAPACITY;
	if (newTail == head)
	    throw new QueueFullException(CAPACITY, item);
	else {
	    data[tail] = item;
	    tail = newTail;
	}
    }

    /** Remove and return the first item in the queue.  Throws
	QueueEmptyException if there are no elements in the queue
	when this method is called.
    */
  public synchronized Object dequeue() throws QueueEmptyException {
      Object result;

      if (isEmpty())
	  throw new QueueEmptyException();
      else {
	  result = data[head];
	  head = (head + 1) % CAPACITY;
	  return result;
      }
  }

    /** Return the object at the head of this queue.  Returns null if the
	queue is empty.  A caller may distinguish between a legitimate null
	item stored in the queue and the result from an empty queue, by
	testing whether the queue is empty with the isEmpty() method.
    */
    public synchronized Object head() {
	if (isEmpty())
	    return null;
	else
	    return data[head];
    }
}

